package com.fzu.normalservice.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.fzu.commonutil.entity.*;
import com.fzu.commonutil.mapper.*;
import com.fzu.commonutil.params.DataResult;
import com.fzu.commonutil.params.SelectResult;
import com.fzu.commonutil.util.*;
import com.fzu.normalservice.client.ThirdPartyClient;
import com.fzu.commonutil.params.DemandMatchParam;
import com.fzu.normalservice.param.DemandParam;
import com.fzu.normalservice.result.DemandResult;
import com.fzu.normalservice.service.CompanyService;
import com.fzu.normalservice.service.DemandService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fzu.normalservice.service.HousekeeperService;
import com.fzu.normalservice.service.ImageService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author zyq
 * @since 2023-03-26
 */
@Service
@RequiredArgsConstructor
public class DemandServiceImpl extends ServiceImpl<DemandMapper, Demand> implements DemandService {
    private final DemandMapper demandMapper;
    private final AddressBookMapper addressBookMapper;
    private final ThirdPartyClient thirdPartyClient;
    private final ServiceTypeMapper serviceTypeMapper;
    private final HousekeeperService housekeeperService;
    private final CompanyService companyService;
    private final HousekeeperMapper housekeeperMapper;
    private final RedisUtil redisUtil;
    private final ImageService imageService;
    private final CompanyMapper companyMapper;

    @Override
    public PageVO page(Demand demand, User user, Integer pageNum, Integer pageSize) {
        // 构造分页参数
        Page<Demand> pageRequest = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<Demand> wrapper = new LambdaQueryWrapper<>();

        Integer role = user.getRole();
        Integer userId = user.getId();
        Integer companyId = user.getCompanyId();
        // 客户只能查看自己的家政需求
        if (CodeEnum.CONSUMER.getCode().equals(role)) {
            wrapper.eq(Demand::getUserId, userId);
        }
        // 公司只能查看自己接的需求以及匹配中的需求
        if (CodeEnum.COMPANY.getCode().equals(role)) {
            wrapper.and(lambda ->
                lambda.eq(Demand::getCompanyId, companyId)
                        .or()
                        .eq(Demand::getState, CodeEnum.MATCHING.getCode())
            );
        }

        Integer accommodation = demand.getAccommodation();
        if (accommodation != null) {
            wrapper.eq(Demand::getAccommodation, accommodation);
        }
        String province = demand.getProvince();
        if (StringUtils.isNotBlank(province)) {
            wrapper.eq(Demand::getProvince, province);
        }
        Integer state = demand.getState();
        if (state != null) {
            wrapper.eq(Demand::getState, state);
        }
        String name = demand.getName();
        if (StringUtils.isNotBlank(name)) {
            wrapper.likeRight(Demand::getName, name);
        }
        String phone = demand.getPhone();
        if (StringUtils.isNotBlank(phone)) {
            wrapper.likeRight(Demand::getPhone, phone);
        }
        wrapper.orderByDesc(Demand::getCreateTime);
        // 进行自定义分页查询
        super.page(pageRequest, wrapper);

        List<Demand> records = pageRequest.getRecords();
        if (!CollectionUtils.isEmpty(records)) {
            Set<Integer> typeIds = records.stream().map(Demand::getServiceTypeId).collect(Collectors.toSet());
            List<ServiceType> typeList = serviceTypeMapper.selectBatchIds(typeIds);
            Map<Integer, String> typeMap = typeList.stream().collect(Collectors.toMap(ServiceType::getId, ServiceType::getName));
            for (Demand record : records) {
                record.setServiceTypeName(typeMap.get(record.getServiceTypeId()));
                record.setTypeUrl(imageService.getServiceTypeUrl(record.getServiceTypeId()));
            }
        }
        return PageVO.convert(pageRequest);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer add(DemandParam param, User user) {
        Integer userId = user.getId();
        Integer role = user.getRole();
        if (!CodeEnum.CONSUMER.getCode().equals(role)) {
            throw new ApiException(ErrorEnum.MESSAGE_ERROR);
        }
        AddressBook addressBook = addressBookMapper.selectById(param.getAddressId());
        if (addressBook == null) {
            throw new ApiException(ErrorEnum.OBJECT_NOT_FOUND);
        }
        String address = addressBook.getProvince() + addressBook.getCity() + addressBook.getTown() + addressBook.getDetail();
        // TODO 百度地图API受限
        R r = thirdPartyClient.getCoordinate(address);
        Map<String, Double> map = (Map<String, Double>)r.getData();
        Demand demand = new Demand()
                .setUserId(userId)
                .setState(CodeEnum.MATCHING.getCode())
                .setAccommodation(param.getAccommodation())
                .setChargeMode(param.getChargeMode())
                .setMaxSalary(param.getMaxSalary())
                .setRemark(param.getRemark())
                .setServiceTypeId(param.getServiceTypeId())
                .setGender(param.getGender())
                .setName(addressBook.getName())
                .setPhone(addressBook.getPhone())
                .setProvince(addressBook.getProvince())
                .setCity(addressBook.getCity())
                .setTown(addressBook.getTown())
                .setDetail(addressBook.getDetail())
                .setLongitude(map.get("lng"))
                .setLatitude(map.get("lat"));
        // TODO 百度地图API受限
        demandMapper.insert(demand);
        // 添加待匹配的需求
        redisUtil.sSet(RedisKey.WAIT_MATCH_DEMAND_ID, demand.getId());
        return demand.getId();
    }

    @Override
    public void cancel(Integer id, User user) {
        Demand demand = super.getById(id);
        if (demand == null) {
            throw new ApiException(ErrorEnum.OBJECT_NOT_FOUND);
        }
        Integer state = demand.getState();
        if (!user.getId().equals(demand.getUserId()) || !CodeEnum.MATCHING.getCode().equals(state)) {
            throw new ApiException(ErrorEnum.MESSAGE_ERROR);
        }
        if (CodeEnum.MATCHING.getCode().equals(state)) {
            // 移除待匹配的需求
            redisUtil.setRemove(RedisKey.WAIT_MATCH_DEMAND_ID, id);
        }
        demand.setState(CodeEnum.CANCELED.getCode());
        super.updateById(demand);
    }

    @Override
    public void flush(Integer id, User user) {
        Demand demand = super.getById(id);
        if (demand == null) {
            throw new ApiException(ErrorEnum.OBJECT_NOT_FOUND);
        }
        Integer state = demand.getState();
        if (!user.getId().equals(demand.getUserId()) || !CodeEnum.MATCHED.getCode().equals(state)) {
            throw new ApiException(ErrorEnum.MESSAGE_ERROR);
        }
        demand.setState(CodeEnum.MATCHING.getCode());
        super.updateById(demand);
        // 添加待匹配的需求
        redisUtil.sSet(RedisKey.WAIT_MATCH_DEMAND_ID, id);
    }

    @Override
    public DemandResult detail(Integer id) {
        Demand demand = demandMapper.selectById(id);
        if (demand == null) {
            throw new ApiException(ErrorEnum.OBJECT_NOT_FOUND);
        }
        DemandResult result = new DemandResult();
        BeanUtils.copyProperties(demand, result);
        ServiceType serviceType = serviceTypeMapper.selectById(demand.getServiceTypeId());
        if (serviceType != null) {
            result.setServiceTypeName(serviceType.getName());
        }
        if (CodeEnum.MATCHED.getCode().equals(demand.getState())) {
            Housekeeper housekeeper = housekeeperService.detail(id);
            if (housekeeper == null) {
                housekeeper = new Housekeeper();
            }
            result.setHousekeeper(housekeeper);
            Company company = companyService.getById(id);
            if (company == null) {
                company = new Company();
            }
            result.setCompany(company);
        }
        return result;
    }

    @Override
    @Async
    public void demandMatch(Integer id) {
        Demand demand = demandMapper.selectById(id);
        if (demand == null) {
            return ;
        }
        // 删除旧数据
        redisUtil.del(RedisKey.DEMAND_MATCHED_HOUSEKEEPER + id);
        List<Housekeeper> housekeeperList = housekeeperMapper.demandMatch(demand);
        Set<Integer> companyIds = housekeeperList.stream().map(Housekeeper::getCompanyId).collect(Collectors.toSet());
        List<Company> companies = companyMapper.selectBatchIds(companyIds);
        Map<Integer, Integer> companyManagerMap = companies.stream().collect(Collectors.toMap(Company::getId, Company::getUserId));
        if (!CollectionUtils.isEmpty(housekeeperList)) {
            for (Housekeeper housekeeper : housekeeperList) {
                housekeeper.setManagerId(companyManagerMap.get(housekeeper.getCompanyId()));
                redisUtil.lSet(RedisKey.DEMAND_MATCHED_HOUSEKEEPER + id, housekeeperService.detail(housekeeper.getId()));
            }
        }
    }

    @Override
    public List<Housekeeper> matchList(Integer id) {
        List<Object> objects = redisUtil.lGet(RedisKey.DEMAND_MATCHED_HOUSEKEEPER + id, 0, -1);
        if (CollectionUtils.isEmpty(objects)) {
            return new ArrayList<>();
        }
        return objects.stream().map(e -> (Housekeeper)e).collect(Collectors.toList());
    }

    @Override
    public void match(DemandMatchParam param) {
        Demand demand = super.getById(param.getDemandId());
        if (demand == null) {
            throw new ApiException(ErrorEnum.OBJECT_NOT_FOUND);
        }
        Integer state = demand.getState();
        if (!CodeEnum.MATCHING.getCode().equals(state)) {
            throw new ApiException(ErrorEnum.STATE_ERROR);
        }
        demand.setState(CodeEnum.MATCHED.getCode());
        demand.setHousekeeperId(param.getHousekeeperId());
        demand.setCompanyId(param.getCompanyId());
        super.updateById(demand);
        // 移除待匹配的需求
        redisUtil.setRemove(RedisKey.WAIT_MATCH_DEMAND_ID, param.getDemandId());
    }

    @Override
    public DataResult demandData(DataResult result, Integer companyId) {
        List<SelectResult> selectResults = demandMapper.sixMonthNewCount(companyId);
        Map<String, Integer> countMap = new HashMap<>(0);
        if (!CollectionUtils.isEmpty(selectResults)) {
            countMap = selectResults.stream().collect(Collectors.toMap(SelectResult::getTotalDate, SelectResult::getTotal));
        }
        List<String> month = DateUtils.getMonth(6);
        List<Integer> count = new ArrayList<>(6);
        for (String s : month) {
            Integer c = countMap.get(s);
            if (c == null) {
                c = 0;
            }
            count.add(c);
        }
        result.setDemandData(count);
        result.setDemandLabel(month);
        LambdaQueryWrapper<Demand> wrapper = new LambdaQueryWrapper<>();
        if (companyId != null) {
            wrapper.eq(Demand::getCompanyId, companyId);
        }
        result.setDemandCount(demandMapper.selectCount(wrapper));
        LambdaQueryWrapper<Demand> wrapper2 = new LambdaQueryWrapper<>();
        wrapper2.eq(Demand::getState, CodeEnum.MATCHING.getCode());
        result.setMatchingDemandCount(demandMapper.selectCount(wrapper2));
        return result;
    }
}
